package com.jcake.vimlike;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

import com.jcake.vimlike.api.ICommand;
import com.jcake.vimlike.internal.CommandManager;
import com.jcake.vimlike.internal.registers.Register;
import com.jcake.vimlike.internal.registers.Register.Type;
import com.jcake.vimlike.preferences.PreferenceConstants;

public class Activator extends AbstractUIPlugin {

	public static final String PLUGIN_ID = "com.jcake.vimlike";

	private static Activator plugin;

	public Activator() {
	}

	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;
		CommandManager commandManager = CommandManager.getInstance();
		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
		IExtensionPoint extensions = extensionRegistry.getExtensionPoint("com.jcake.vimlike.commands");
		for (IConfigurationElement configurationElement : extensions.getConfigurationElements()) {
			String clazz = configurationElement.getAttribute("class");
			Class<?> clazzz = Class.forName(clazz);
			Object newInstance = clazzz.newInstance();
			commandManager.registerCommand((ICommand) newInstance);
		}

		restoreRegisters();
	}

	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);

		storeRegisters();
	}

	private void restoreRegisters() {
		if (!shouldPersistRegisters()) {
			return;
		}
		File savedRegistersLocation = getSavedRegistersLocation();
		if (!savedRegistersLocation.exists()) {
			return;
		}
		try {
			XMLMemento memento = XMLMemento.createReadRoot(new InputStreamReader(new FileInputStream(savedRegistersLocation), "UTF-8"));
			IMemento[] registers = memento.getChildren("register");
			for (IMemento registerMemento : registers) {
				String registerName = registerMemento.getString("name");
				String registerType = registerMemento.getString("type");
				String registerContent = registerMemento.getTextData();
				RegisterManager registerManager = RegisterManager.getInstance();
				registerManager.updateRegister(registerName.charAt(0), registerContent, Type.valueOf(registerType));
			}
		} catch (WorkbenchException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	private void storeRegisters() {
		if (!shouldPersistRegisters()) {
			File registersLocation = getSavedRegistersLocation();
			if (registersLocation.exists()) {
				registersLocation.delete();
			}
			return;
		}
		XMLMemento memento = XMLMemento.createWriteRoot("VimLikeRegisters");
		RegisterManager instance = RegisterManager.getInstance();
		List<Register> registers = instance.getRegisters();
		for (Register register : registers) {
			if (register.getContent() == null || "".equals(register.getContent())) {
				continue;
			}
			IMemento registerMemento = memento.createChild("register");
			registerMemento.putString("name", String.valueOf(register.getName()));
			if (register.getType() != null) {
				registerMemento.putString("type", register.getType().name());
			}
			registerMemento.putTextData(register.getContent());
		}

		try {
			File registersLocation = getSavedRegistersLocation();
			memento.save(new OutputStreamWriter(new FileOutputStream(registersLocation), "UTF-8"));
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private boolean shouldPersistRegisters() {
		return getPreferenceStore().getBoolean(PreferenceConstants.P_SAVE_REGISTERS_ON_EXIT);
	}

	private File getSavedRegistersLocation() {
		return new File(getStateLocation().toFile(), "registers.xml");
	}

	public static Activator getDefault() {
		return plugin;
	}

}
